<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div>打开控制台查看输出结果</div>

    <script>
        console.log('====RegExp()=======');
        /* RegExp构造函数 */
        /* 
        new RegExp('abc','i') 
        等价于  
        /abc/i 
        */
        let regex = new RegExp('abc', 'i')
        let regex2 = /abc/i
        let s = 'abc'
        console.log(regex.test(s) == regex2.test(s));
        /* 在es5中，如果第一个参数是一个正则，第二个是修饰会报错 */
        // let regex3 = new RegExp(/abc/,'i')  // 这种写法在es5报错

        /* es6改变了这种行为，如果第一个是正则，第二个参数可以使用修饰符，并且返回
           的正则表达式会忽略原有的正则表达式修饰符，只使用新指定的修饰符
        */
        let regex4 = new RegExp(/abc/ig, 'i') // 这里的ig修饰符会被第二个参数 i 覆盖，最后的结果为/abc/i

        console.log('======u 修饰符========');
        /* es6对正则表达式添加了u修饰符，表示为==Unicode模式==，用来处理大于\uFFFF的Unicode字符 */
        console.log(/^\uD83D/u.test('\uD83D\uDC2A')); // false 这里加上u.变成了es6支持，可以将\uD83D\uDC2A转译为一个字符，比对不匹配返回false
        console.log(/^\uD83D/.test('\uD83D\uDC2A')); // true  这里没有加u.为es5支持，无法识别4个字节的UTF-16编码。会将\uD83D\uDC2A识别为两个字符，比对的时候其中的字符匹配，所以返回true

        /* 点字符 */
        console.log('===点字符=====');
        // 点字符在正则表达式中，表示除了换行符以外的任意单个字符，但对于码点大于0*FFFF的字符，点字符串无法识别，必须前面加上u修饰符
        let z = '正'
        console.log(/^.$/.test(z));
        console.log(/^.$/u.test(z));

        console.log('====Unicode 字符表示法====');
        /* es6新增了大括号表示unicode字符，这种字符在正则中必须使用 u 修饰符才能识别否则会被解读为量词,量词是无法识别大于0xFFFF的unicode字符的。 */
        console.log(/\u{61}/.test('a')); // false
        console.log(/\u{61}/u.test('a')); // true

        console.log('====i 修饰符====');
        /* i 修饰符为不区分大小写，对于大于0xFFFF的unicode的修饰符,后面需要加上 u  */
        console.log(/[a-z]/i.test('\u212A')); // false 
        console.log(/[a-z]/iu.test('\u212A')); // true

        console.log('====y 修饰符===');
        /* 
        y修饰符，即为 粘连(sticky)修饰符
        在正则匹配中，g为全局匹配，没有位置限制
        y则有位置限制，必须在上一次匹配完后的下一个字符串的的第一位开始匹配
        */
        let a = 'aaa-aa-a'
        let r = /a+/y
        let r2 = /a+/g
        console.log(r.exec(a)); // aaa
        console.log(r2.exec(a)); // aaa
        // 第二次匹配 y在上次匹配完后的第一个位置开始匹配，字符串 - 无法匹配上
        console.log(r.exec(a)); // null  // 其实只需要修改一下正则保证每次匹配上就行了 /a+-/y
        console.log(r2.exec(a)); // aa

        // RegExp.prototype.sticky 用来检查是否设置了 y 修饰符
        let a1 = /heelo\d/y
        console.log(a1.sticky); // true


        console.log('===检测正则表达式修饰符以及正文===');
        /* 
        source 返回正则匹配规则
        flags 返回正则的修饰符
        */
        let rul = /abc/ig
        console.log(rul.source); // abc
        console.log(rul.flags); // ig


        console.log(' ==== s 修饰符 ： dotAll模式');
        /* 
          正则表达式中，点(.)是一个特殊字符，代表任意字符，但是有两种例外
          第一种：四个字节的UTF-16字符，这个使用 u 修饰符解决
          第二种：行终止符，使用 s 修饰符解决
        */
        /* 行终止符，就是该字符表示一行的终结。以下四个字符属于“行终止符”。
        U+000A 换行符（\n）
        U+000D 回车符（\r）
        U+2028 行分隔符（line separator）
        U+2029 段分隔符（paragraph separator） */
        let f = /foo.bar/.test('foo\nbar')
        console.log(f); // false // 因为.不匹配 \n ,所以正则表达式返回false
        // 解决方法 : s 修饰符
        /* 使用s修饰符，可以使 . 匹配任意单个字符 */
        let f2 = /foo.bar/s.test('foo\nbar')
        console.log(f2); // true
        /* 
        这种s修饰符的模式被称为dotAll模式，dot就是代表一切字符
        所以，正则表达式还引入了dotAll属性，检查该表达式是否开启了dotAll模式
         */
        let f3 = /foo.bar/s
        console.log(f3.dotAll); // true

        console.log('====先行断言==后行断言===');
        console.log('==先行断言==');
        /* 先行断言指的是，x在y前面才匹配
           /x(?=y)/   x在y符号前才匹配
        */
        let look = '100% 东方不败'
        console.log(/\d+(?=%)/.exec(look)); // 100
		let look2 = '100! 东方不败'
		console.log(/\d+(?=%)/.exec(look2));  // null 没有匹配到%前的数字
		
		/* 
		 后行断言
		 与先行断言相反，x在y后面时才匹配
		 /(?<=y)x/
		  ? 后面 跟 <= 条件y   
		 */
		let look3 = '东方不败 $100 西方求败'
		console.log(/(?<=\$)\d+/.exec(look3)); // 100  表示在\$后的字符才会被匹配
		/* 注意
		   先行断言和后行断言的条件是不计入返回结果的
		 */
		
		
    </script>
</body>

</html>